package com.tsmti.tags.form;

import javax.servlet.jsp.JspException;

import com.tsmti.core.common.constant.Constants;
import com.tsmti.core.util.SpringContextUtils;
import com.tsmti.tags.form.support.CustomBindStatus;
import com.tsmti.tags.html.manager.HtmlComponentManager;
import com.tsmti.util.DictionaryUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.BindStatus;
import org.springframework.web.servlet.tags.form.TagWriter;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @Package：com.tsmti.tags.form
 * @Class：RadioButtonsTag
 * @Description： TODO
 * @Author：
 * @Date：Created in 2018/3/14 17:15
 * @Company:
 * @Version：
 * @Modified By:
 */
@SuppressWarnings("serial")
public class RadioButtonsTag extends org.springframework.web.servlet.tags.form.RadioButtonsTag {
	protected HtmlComponentManager htmlComponentManager = SpringContextUtils.getApplicationContext()
			.getBean(HtmlComponentManager.class);
	/**是否嵌套使用Form自定的模型，模式为真,*/
	private BindStatus bindStatus = null;
	/**nested为false,需要设置对应字段为空字符串否则报错；*/
	private Boolean nested = true;
	/**绑定数据字典类型，数据字典优先*/
	private String dict = "";
	/**1,bean 2,通过参数获取。3.获取getAttribute中的值*/
	private String valueway = "";
	/**当所有值都无效的时候，是由默认值*/
	private String defaultValue = "";

	@Override
	protected BindStatus getBindStatus() throws JspException {
		if (this.bindStatus == null) {
			String nestedPath = "";
			if (nested) {
				nestedPath = getNestedPath();
			}
			String pathToUse = (nestedPath != null ? nestedPath + getPath() : getPath());
			if (pathToUse.endsWith(PropertyAccessor.NESTED_PROPERTY_SEPARATOR)) {
				pathToUse = pathToUse.substring(0, pathToUse.length() - 1);
			}
			this.bindStatus = CustomBindStatus.create(pageContext, pathToUse, getRequestContext(), false, nested,
					valueway, defaultValue);
		}
		return this.bindStatus;
	}

	@Override
	protected int writeTagContent(TagWriter tagWriter) throws JspException {
		Object items = this.getItems();
		Object itemsObject = items instanceof String ? this.evaluate("items", items) : items;
		String itemValue = this.getItemValue();
		String itemLabel = this.getItemLabel();
		String valueProperty = itemValue != null ? ObjectUtils.getDisplayString(this.evaluate("itemValue", itemValue)) : null;
		String labelProperty = itemLabel != null ? ObjectUtils.getDisplayString(this.evaluate("itemLabel", itemLabel)) : null;
		Class<?> boundType = this.getBindStatus().getValueType();
		if (itemsObject == null && boundType != null && boundType.isEnum()) {
			itemsObject = boundType.getEnumConstants();
		}

		if (itemsObject == null) {
			throw new IllegalArgumentException("Attribute 'items' is required and must be a Collection, an Array or a Map");
		} else {
			int itemIndex;
			if (itemsObject.getClass().isArray()) {
				Object[] itemsArray = (Object[])((Object[])itemsObject);

				for(itemIndex = 0; itemIndex < itemsArray.length; ++itemIndex) {
					Object item = itemsArray[itemIndex];
					this.writeObjectEntry(tagWriter, valueProperty, labelProperty, item, itemIndex);
				}
			} else {
				Iterator it;
				if (itemsObject instanceof Collection) {
					Collection<?> optionCollection = (Collection)itemsObject;
					itemIndex = 0;

					for(it = optionCollection.iterator(); it.hasNext(); ++itemIndex) {
						Object item = it.next();
						this.writeObjectEntry(tagWriter, valueProperty, labelProperty, item, itemIndex);
					}
				} else {
					if (!(itemsObject instanceof Map)) {
						throw new IllegalArgumentException("Attribute 'items' must be an array, a Collection or a Map");
					}

					Map<?, ?> optionMap = (Map)itemsObject;
					itemIndex = 0;

					for(it = optionMap.entrySet().iterator(); it.hasNext(); ++itemIndex) {
						Map.Entry entry = (Map.Entry)it.next();
						this.writeMapEntry(tagWriter, valueProperty, labelProperty, entry, itemIndex);
					}
				}
			}
			return 0;
		}
	}
	private void writeObjectEntry(TagWriter tagWriter, String valueProperty, String labelProperty, Object item, int itemIndex) throws JspException {
		BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(item);
		Object renderValue;
		if (valueProperty != null) {
			renderValue = wrapper.getPropertyValue(valueProperty);
		} else if (item instanceof Enum) {
			renderValue = ((Enum)item).name();
		} else {
			renderValue = item;
		}

		Object renderLabel = labelProperty != null ? wrapper.getPropertyValue(labelProperty) : item;
		this.writeElementTag(tagWriter, item, renderValue, renderLabel, itemIndex);
	}
	private void writeMapEntry(TagWriter tagWriter, String valueProperty, String labelProperty, Map.Entry<?, ?> entry, int itemIndex) throws JspException {
		Object mapKey = entry.getKey();
		Object mapValue = entry.getValue();
		BeanWrapper mapKeyWrapper = PropertyAccessorFactory.forBeanPropertyAccess(mapKey);
		BeanWrapper mapValueWrapper = PropertyAccessorFactory.forBeanPropertyAccess(mapValue);
		Object renderValue = valueProperty != null ? mapKeyWrapper.getPropertyValue(valueProperty) : mapKey.toString();
		Object renderLabel = labelProperty != null ? mapValueWrapper.getPropertyValue(labelProperty) : mapValue.toString();
		this.writeElementTag(tagWriter, mapKey, renderValue, renderLabel, itemIndex);
	}

	private void writeElementTag(TagWriter tagWriter, Object item, Object value, Object label, int itemIndex) throws JspException {
		tagWriter.startTag(this.getElement());
		if (itemIndex > 0) {
			Object resolvedDelimiter = this.evaluate("delimiter", this.getDelimiter());
			if (resolvedDelimiter != null) {
				tagWriter.appendValue(resolvedDelimiter.toString());
			}
		}

		tagWriter.startTag("input");
		String id = this.resolveId();
		this.writeOptionalAttribute(tagWriter, "id", id);
		this.writeOptionalAttribute(tagWriter, "name", this.getName());
		this.writeOptionalAttribute(tagWriter, "title", this.convertToDisplayString(label));
		this.writeOptionalAttributes(tagWriter);
		tagWriter.writeAttribute("type", this.getInputType());
		this.renderFromValue(item, value, tagWriter);
		tagWriter.endTag();
		tagWriter.endTag();
	}
	public Boolean getNested() {
		return nested;
	}

	public void setNested(Boolean nested) {
		this.nested = nested;
	}

	public String getDict() {
		return dict;
	}

	public void setDict(String dict) {
		this.dict = dict;
	}

	public String getValueway() {
		return valueway;
	}

	public void setValueway(String valueway) {
		this.valueway = valueway;
	}

	public String getDefaultValue() {
		return defaultValue;
	}

	public void setDefaultValue(String defaultValue) {
		this.defaultValue = defaultValue;
	}

	@Override
	protected Object getItems() {
		if (!StringUtils.isEmpty(dict)) {
			return DictionaryUtils.getDictList(dict);
		}
		return super.getItems();
	}

	@Override
	protected String getItemLabel() {
		if (!StringUtils.isEmpty(dict)) {
			return "name";
		}
		return super.getItemLabel();
	}

	@Override
	protected String getItemValue() {
		if (!StringUtils.isEmpty(dict)) {
			return "code";
		}
		return super.getItemValue();
	}

	@Override
	public void doFinally() {
		super.doFinally();
		this.bindStatus = null;
	}
}
